<canvas></canvas>
<script src="ogc-parser.js"></script>
<script>
/* global ogcParser */
function wait(ms = 0) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

// # need to draw to 2nd canvas, then shave off non perfect pixels

async function main() {
  const ctx = document.querySelector('canvas').getContext('2d');
  ctx.canvas.width = 2048;
  ctx.canvas.height = 2048;
  ctx.fillStyle = '#444';
  ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
  ctx.scale(ctx.canvas.width / 360, ctx.canvas.height / -180);

  function setColor(color) {
    ctx.fillStyle = color;
    ctx.strokeStyle = color;
  }

  const handlers = {
    point,
    lineString,
    polygon,
    multiPoint,
    multiLineString,
    multiPolygon,
  };

  function point(d) {
    ctx.fillRect(...d.point, 1, 1);
  }

  function setPathFromPoints(points, backward = false) {
    if (backward) {
      const numPoints = points.length / 2;
      const lastPoint = numPoints - 1;
      ctx.moveTo(...points.slice(lastPoint * 2, lastPoint * 2 + 2));
      for (let i = lastPoint - 1; i >= 0; i -= 2) {
        ctx.lineTo(...points.slice(i * 2, i * 2 + 2));
      }
    } else {
      ctx.moveTo(...points.slice(0, 2));
      for (let i = 2; i < points.length; i += 2) {
        ctx.lineTo(...points.slice(i, i + 2));
      }
    }
  }

  function stroke(ctx) {
    ctx.save();
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.stroke();
    ctx.restore();
  }

  function lineString(d) {
    ctx.beginPath();
    setPathFromPoints(d.points);
    stroke(ctx);
  }

  function polygon(d) {
    ctx.beginPath();
    d.rings.forEach((ring, ndx) => {
      setPathFromPoints(ring, ndx !== 0);
      ctx.closePath();
    });
    ctx.fill();
    stroke(ctx);
  }

  function multiPoint(d) {
    for (let i = 0; i < d.points.length; i += 2) {
      ctx.fillRect(...d.points.slice(i, i + 2));
    }
  }

  function multiLineString(d) {
    d.lineStrings.forEach((lineString) => {
      ctx.beginPath();
      setPathFromPoints(lineString);
      stroke(ctx);
    });
  }

  function multiPolygon(d) {
    d.polygons.forEach((polygon) => {
      ctx.beginPath();
      polygon.forEach((ring, ndx) => {
        setPathFromPoints(ring, ndx !== 0);
      });
      ctx.fill();
      stroke(ctx);
    });
  }

  const colors = {};

  const req = await fetch('level1.json');
  const areas = await req.json();
  const min = [Number.MAX_VALUE, Number.MAX_VALUE];
  const max = [Number.MIN_VALUE, Number.MIN_VALUE];
  console.log('num areas:', areas.length);
  for (let ndx = 0; ndx < areas.length; ++ndx) {
    const area = areas[ndx];
    try {
      const buf = new Uint8Array(base64ToUint8Array(area.geom));
      area.geom = ogcParser.parse(buf);
    } catch (e) {
      console.log('ERROR:', e);
      console.log(JSON.stringify(area, null, 2));
      throw e;
    }

    if (!colors[area.NAME_0]) {
      colors[area.NAME_0] = rgb(r(), r(), r());
    }

    const color = colors[area.NAME_0];

    console.log(ndx, area.NAME_0);

    area.geom.primitives.forEach((primitive) => {
      const fn = handlers[primitive.type];
      setColor(color);
      fn(primitive);
    });

    min[0] = Math.min(min[0], area.geom.envelope[0]);
    min[0] = Math.min(min[0], area.geom.envelope[1]);
    min[1] = Math.min(min[1], area.geom.envelope[2]);
    min[1] = Math.min(min[1], area.geom.envelope[3]);

    max[0] = Math.max(max[0], area.geom.envelope[0]);
    max[0] = Math.max(max[0], area.geom.envelope[1]);
    max[1] = Math.max(max[1], area.geom.envelope[2]);
    max[1] = Math.max(max[1], area.geom.envelope[3]);

    if (ndx % 100 === 99) {
      await wait();
    }
  }

  console.log('min', min);
  console.log('max', max);
}

function r(min, max) {
  if (min === undefined) {
    min = 0;
    max = 1;
  } else if (max === undefined){
    max = min;
    min = 0;
  }
  return min + Math.random() * (max - min);
}

function rgb(r, g, b) {
  return `rgb(${r * 255 | 0},${g * 255 | 0},${b * 255 | 0})`;
}

// function hsl(h, s, l) {
//   return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
// }

function base64ToUint8Array(base64) {
  const raw = window.atob(base64);
  const rawLength = raw.length;
  const array = new Uint8Array(new ArrayBuffer(rawLength));

  for(let i = 0; i < rawLength; ++i) {
    array[i] = raw.charCodeAt(i);
  }

  return array;
}

main();

</script>
